package BusquedaLocal;
import IA.Bicing.Bicing;

public class Board {
    public class Furgo{
        //cada int indica el numero de la parada(indice en el vector Data)
        int EstInicial; //-1 Indica que la furgo no se usa
        int bicis0;
        int Parada_1;
        int bicis1;
        int Parada_2;
        
        public Furgo() {
            EstInicial = -1;
            Parada_1 = -1;
            Parada_2 = -1;
            bicis0 = 0;
            bicis1 = 0;
        }

        public Furgo(Furgo f) {
            EstInicial = f.EstInicial;
            Parada_1 = f.Parada_1;
            Parada_2 = f.Parada_2;
            bicis0 = f.bicis0;
            bicis1 = f.bicis1;
        }
    };
    //public class IABicing{
        public class EstacionData {
            int x,y;
            int BicisIniciales;
            int transportadas;
            int no_movidas;
            int Bicis_movidas;
            int DebeHaber;
            boolean visitada;
            
            public EstacionData(Bicing b, int estacion) {
                int dat[] = b.getStationCoord(estacion);
                x= dat[0];
                y = dat[1];
                BicisIniciales = b.getStationNextState(estacion);
                DebeHaber = b.getDemandNextHour(estacion);
                no_movidas = b.getStationDoNotMove(estacion);
                Bicis_movidas = 0;
                transportadas = 0;
                b.getDemandNextHour(estacion);
                visitada = false;
            }

            public EstacionData(EstacionData ed) {
                x = ed.x;
                y = ed.y;
                BicisIniciales = ed.BicisIniciales;
                DebeHaber = ed.DebeHaber;
                transportadas = ed.transportadas;
                visitada = ed.visitada;
                no_movidas = ed.no_movidas;
                Bicis_movidas = ed.Bicis_movidas;
            }
        };
        private EstacionData[] Data;
        private Furgo[] F;
        private double Ganancias;
        private Bicing b;

        public Board(Bicing b, int num_furgonetas) {
            this.b = b;
            int num_est = b.getNumStations();
            Data = new EstacionData[num_est];
            for (int i = 0; i<num_est; i++) {
                Data[i] = new EstacionData(b,i);
            }
            F = new Furgo[num_furgonetas];
            for (int i =0; i<num_furgonetas; i++) {
                F[i] = new Furgo();
            }
            Ganancias = 0;
        }
        
        public Board(Board bo) {
            b = bo.b;
            Data = new EstacionData[bo.Data.length];
            for (int i =0; i<bo.Data.length; i++) {
                Data[i] = new EstacionData(bo.Data[i]);
            }
            F = new Furgo[bo.F.length];
            for (int i =0; i<bo.F.length; i++) {
                F[i] = new Furgo(bo.F[i]);
            }
        }

        public double Calcular_Ganancias() {
            int num_est = Data.length;
            Ganancias = 0;
            for (int i = 0; i<num_est; i++) {
                int max_g = Data[i].DebeHaber - Data[i].BicisIniciales;
                if (max_g > 0 && max_g < Data[i].transportadas)
                    Ganancias = Ganancias + max_g;
                else Ganancias = Ganancias + Data[i].transportadas;
            }
            int num_furgonetas = F.length;
            for (int i =0; i<num_furgonetas; i++) {
                if (F[i].Parada_1 != -1) {
                    double distancia = b.getStationsDistance(F[i].EstInicial,F[i].Parada_1);
                    Ganancias = Ganancias - ((F[i].bicis0/10)+1)*distancia;
                }
                if (F[i].Parada_2 != -1) {
                    double distancia = b.getStationsDistance(F[i].Parada_1,F[i].Parada_2);
                    Ganancias = Ganancias - ((F[i].bicis1/10)+1)*distancia;
                }
            }
            //System.out.println(Ganancias);
            return Ganancias;
        }

        /*PRE: bicis_transportadas no incumple ninguna regla, e1 puede abastecer esa cantidad sin perdidas y es la cantidad
        justa de bicis necesarias para ser transportadas.
        */
        void transporta(int furgoneta, int bicis_transportadas, int e1, int e2, int e3) {
            Data[e1].Bicis_movidas = Data[e1].Bicis_movidas+bicis_transportadas;
            Data[e1].no_movidas = Data[e1].no_movidas - bicis_transportadas;
            Data[e1].visitada = true;
            F[furgoneta].bicis0 = bicis_transportadas;
            F[furgoneta].EstInicial = e1;
            int bicis_sobrantes2 = Data[e2].BicisIniciales+Data[e2].transportadas-Data[e2].DebeHaber-Data[e2].Bicis_movidas;
            if (bicis_sobrantes2 < 0) {
                if (bicis_transportadas >= -1*bicis_sobrantes2) {
                    F[furgoneta].Parada_1 = e2;
                    Data[e2].transportadas = Data[e2].transportadas-bicis_sobrantes2;
                    bicis_transportadas = bicis_transportadas + bicis_sobrantes2;
                    F[furgoneta].bicis1 = bicis_transportadas;
                    if (bicis_transportadas > 0) {
                        F[furgoneta].Parada_2 = e3;
                        Data[e3].transportadas = Data[e3].transportadas+bicis_transportadas;
                        F[furgoneta].bicis1 = bicis_transportadas;
                    }
                    else {
                        F[furgoneta].Parada_2 = -1;
                        F[furgoneta].bicis1 = 0;
                    }
                }
                else {
                    F[furgoneta].Parada_1 = e2;
                    Data[e2].transportadas = Data[e2].transportadas+bicis_transportadas;
                    F[furgoneta].Parada_2 = -1;
                    F[furgoneta].bicis1 = 0;
                }
            }
            else {
                F[furgoneta].Parada_1 = e3;
                Data[e3].transportadas = Data[e3].transportadas+bicis_transportadas;
                F[furgoneta].Parada_2 = -1;
                F[furgoneta].bicis1 = 0;
            }
        }

        void asignar_destinos(int furgoneta, int e1, int e2, int e3) {
            boolean destino3 = true;
            if (e3 == -1) destino3 = false;
            int bicis_sobrantes1 = Data[e1].BicisIniciales+Data[e1].transportadas-Data[e1].DebeHaber-Data[e1].Bicis_movidas;
            int bicis_sobrantes2 = Data[e2].BicisIniciales+Data[e2].transportadas-Data[e2].DebeHaber-Data[e2].Bicis_movidas;
            int bicis_sobrantes3 = 0;
            if (destino3)
                bicis_sobrantes3 = Data[e3].BicisIniciales+Data[e3].transportadas-Data[e3].DebeHaber-Data[e3].Bicis_movidas;
            if (bicis_sobrantes1 > Data[e1].no_movidas) bicis_sobrantes1 = Data[e1].no_movidas;
            if (bicis_sobrantes1 > 0 && (bicis_sobrantes2 < 0 || bicis_sobrantes3 < 0)) {
                int total_transporte = 0;
                if (bicis_sobrantes2 < 0 && bicis_sobrantes3 < 0)total_transporte= -1*(bicis_sobrantes2+bicis_sobrantes3);
                else if (bicis_sobrantes2<0) total_transporte= -1*bicis_sobrantes2;
                else if (bicis_sobrantes3<0) total_transporte= -1*bicis_sobrantes3;
                if (total_transporte >= 30) total_transporte = 30;
                if (total_transporte < bicis_sobrantes1) {
                    transporta(furgoneta,total_transporte,e1,e2,e3);
                }
                else {
                    transporta(furgoneta,bicis_sobrantes1,e1,e2,e3);
                }
            }
            else {
                F[furgoneta].EstInicial = -1;
                F[furgoneta].Parada_1 = -1;
                F[furgoneta].Parada_2 = -1;
                F[furgoneta].bicis0 = 0;
                F[furgoneta].bicis1 = 0;
            }
        }

        public boolean estacion_asignada(int estacion) {
            return Data[estacion].visitada;
        }

        public int numero_furgonetas() {
            return F.length;
        }

        public int numero_estaciones() {
            return Data.length;
        }

        public boolean utilizada(int furgoneta) {
            return (F[furgoneta].EstInicial != -1);
        }
        
        public String datos_furgoneta(int furgoneta) {
            String s="Furgo: "+(furgoneta+1)+"\n";
            int dest1 = F[furgoneta].EstInicial;
            int dest2 = F[furgoneta].Parada_1;
            int dest3 = F[furgoneta].Parada_2;
            if (F[furgoneta].Parada_1!=-1) {
                s+="Inicio: "+(dest1+1)+"\n";
                s+="    Bicis_iniciales: "+(Data[dest1].BicisIniciales);
                s+=" Bicis_previstas: "+Data[dest1].DebeHaber;
                s+=" Bicis _totales: "+(Data[dest1].transportadas+Data[dest1].BicisIniciales-Data[dest1].Bicis_movidas)+"\n";
                s+="Destino1: "+(dest2+1)+" Bicis_transportadas: "+F[furgoneta].bicis0+"\n";
                s+="    Bicis_iniciales: "+(Data[dest2].BicisIniciales);
                s+=" Bicis_previstas: "+Data[dest2].DebeHaber;
                s+=" Bicis _totales: "+(Data[dest2].transportadas+Data[dest2].BicisIniciales-Data[dest2].Bicis_movidas)+"\n";
            }
            else s+="No hay inicio\n";
            if (F[furgoneta].Parada_2!=-1) {
                s+="Destino2: "+(dest3+1)+" Bicis_transportadas: "+F[furgoneta].bicis1+"\n";
                s+="    Bicis_iniciales: "+(Data[dest3].BicisIniciales);
                s+=" Bicis_previstas: "+Data[dest3].DebeHaber;
                s+=" Bicis _totales: "+(Data[dest3].transportadas+Data[dest3].BicisIniciales-Data[dest3].Bicis_movidas)+"\n";
            }
            else s+="No hay segundo destino\n";
            s+="Ganancias: "+Calcular_Ganancias();
            return s;
        }
    }

